import execjs
from fontTools.ttLib import TTFont

num_order = {"range": [1764, 1964], "value": ["1", "4", "7", "2", "5", "8", "0", "3", "6", "9"]}
letter_order = {"range": [1504, 1764],
                "value": ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S",
                          "T",
                          "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
                          "n",
                          "o", "p", "q", "r", "s", "t",
                          "u", "v", "w", "x", "y", "z"]}
chinese_order = {"range": [4, 1504],
                 "value": ["七", "万", "三", "上", "专", "九", "二", "元", "八", "六", "区", "十", "口", "和", "态", "本", "林",
                           "汉", "注", "火", "考", "言", "讯", "身", "输", "迅", "像", "艺", "包", "据", "印", "探", "及", "营",
                           "命", "历", "曲", "服", "机", "境", "械", "磁", "飞", "食", "备", "植", "空", "武", "设", "水", "居",
                           "油", "洋", "测", "纽", "统", "件", "软", "轻", "美", "丁", "下", "与", "世", "业", "丝", "中", "主",
                           "义", "乌", "书", "事", "互", "交", "产", "人", "仪", "价", "休", "会", "伤", "伦", "估", "体", "作",
                           "供", "侦", "俄", "保", "信", "修", "健", "儿", "光", "克", "党", "全", "公", "共", "关", "兵", "其",
                           "军", "农", "准", "减", "出", "分", "划", "则", "别", "制", "刷", "力", "功", "加", "务", "动", "助",
                           "劳", "化", "医", "华", "卫", "发", "古", "史", "司", "合", "告", "品", "商", "回", "国", "土", "地",
                           "型", "培", "声", "大", "天", "女", "媒", "子", "学", "安", "定", "宝", "实", "审", "室", "家", "宾",
                           "密", "小", "少", "尔", "展", "属", "嵌", "工", "市", "师", "广", "应", "康", "建", "开", "录", "形",
                           "影", "律", "微", "德", "心", "情", "想", "感", "成", "战", "房", "技", "投", "护", "报", "拉", "控",
                           "推", "播", "收", "放", "政", "教", "数", "文", "料", "斯", "无", "日", "时", "景", "智", "术", "材",
                           "村", "来", "查", "正", "民", "气", "污", "河", "治", "法", "泰", "海", "源", "灾", "炸", "然", "照",
                           "爆", "版", "物", "环", "班", "理", "生", "用", "画", "界", "疗", "监", "知", "石", "研", "种", "科",
                           "秘", "移", "程", "税", "立", "筑", "算", "管", "类", "精", "纺", "组", "织", "经", "网", "职", "育",
                           "能", "自", "航", "船", "英", "草", "萄", "葡", "行", "表", "装", "观", "规", "视", "计", "论", "评",
                           "识", "译", "试", "语", "财", "质", "资", "路", "车", "轨", "轮", "运", "通", "造", "采", "量", "金",
                           "鉴", "间", "非", "韩", "项", "预", "饰", "馆", "验", "高", "麻"]}


def __create_decrypt_map():
    decrypt_map = {}
    font_map = [num_order, letter_order, chinese_order]
    for item in font_map:
        index = 0
        for i in range(item['range'][0], item['range'][1]):
            decrypt_map[str(i)] = item['value'][index]
            index += 1
            if index % len(item['value']) == 0:
                index = 0
    return decrypt_map


def __convert_id_2_font(font_id):
    decrypt_map = __create_decrypt_map()
    try:
        num = decrypt_map[str(font_id)]
    except Exception as e:
        pass
    return num


def convert_encrypt_str(encrypted_str):
    js = '''
        function cnDeCryptV2(str) {
            var k = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", l = k.length, b, b0, b1, b2, b3, d = 0, s;
            s = new Array(Math.floor(str.length / 4)),
            b = s.length;
            for (var i = 0; i < b; i++)
                b0 = k.indexOf(str.charAt(d)),
                d++,
                b1 = k.indexOf(str.charAt(d)),
                d++,
                b2 = k.indexOf(str.charAt(d)),
                d++,
                b3 = k.indexOf(str.charAt(d)),
                d++,
                s[i] = ((b1 + b0 * l) * l + b2) * l + b3;
            b = eval("String.fromCharCode(" + s.join(",") + ")");
            var w = "";
            return b.split("|").forEach((function(e, t) {
                t > 0 && (-1 != e.search(/【(.*?)】/) ? w += e.replace("【", "").replace("】", "") : e.length > 0 && (w += "&#x" + e + ";"))
            }
            )),
            w
        }
    '''
    ctx = execjs.compile(js)
    return ctx.call("cnDeCryptV2", encrypted_str)


def decrypt_font(encrypt_data):
    '''
    &#xd02a;&#xd048;&#xd01f;
    :param encrypt_data:
    :return:
    '''
    encrypt_data = convert_encrypt_str(encrypt_data)
    encrypt_data_list = encrypt_data.split(";")
    data_list = []
    for data in encrypt_data_list:
        data_list += data.split("&")
    result = [x for x in data_list if x != '']
    _font = TTFont('yfe2.woff2')
    font_map = __get_font_map(_font)
    decrypt_value = []
    for item in result:
        if "#" in item:
            item = item.replace("#", "0")
            font_value = font_map[item]
            glyph_id = _font.getGlyphID(font_value)
            char = __convert_id_2_font(glyph_id)
            decrypt_value.append(char)
        else:
            decrypt_value.append(item)
    return "".join(decrypt_value)


def __get_font_map(_font):
    font_map = _font.getBestCmap()
    new_font_map = {}
    for index, key in enumerate(font_map):
        new_font_map[hex(key)] = font_map[key]
    return new_font_map
#x7895

encrypt_data = "001I002U001L001J001C001J001C001F001F001E001K0037001L002U001H001I003G002R002T001H001F003G09HS0FFG09HT003G002R002Q002U001K003G002R002P001I002R003G002R002P002Q001J003G002R002P002Q002R"
print(decrypt_font(encrypt_data))
